package com.icbc.dccsh.bolt;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.storm.redis.common.mapper.RedisDataTypeDescription;
import org.apache.storm.redis.common.mapper.RedisLookupMapper;

import com.google.common.collect.Lists;
import com.icbc.dccsh.functions.AverageFunction;
import com.icbc.dccsh.functions.FormulaEngine;
import com.icbc.dccsh.functions.SumFunction;
import com.icbc.dccsh.util.Watcher;

import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.ITuple;
import backtype.storm.tuple.Values;
import flexjson.JSONDeserializer;
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;

public class GerFormulaMapper implements RedisLookupMapper {
	private RedisDataTypeDescription description;
	private Watcher _watcher = null;
	// private int counter = 0;

	public GerFormulaMapper() {
		description = new RedisDataTypeDescription(RedisDataTypeDescription.RedisDataType.STRING, null);
		this._watcher = Watcher.getWatcher("GerFormulaMapper");
	}

	private static flexjson.JSONDeserializer d = new flexjson.JSONDeserializer();

	public List<Values> toTuple(ITuple input, Object value) {
		HashMap<String, Object> input_hashmap = null;
		HashMap<String, Object> mapping_hash = null;
		this._watcher.count();
		try {
			input_hashmap = (HashMap<String, Object>) input.getValueByField("hash");
			// HashMap<String, Double> result_hashmap = new HashMap<String,
			// Double>();
			if (StringUtils.isEmpty((String) value)) {
				System.out.println(String.format("mapping for key [%s] not found...", getKey(input)));
			}

			mapping_hash = (HashMap<String, Object>) d.deserialize((String) value);
		} catch (RuntimeException ex) {
			System.out.println(
					String.format("processing value [%s] for key [%s] error...", (String) value, getKey(input)));
			throw ex;
		}
		// ArrayList metricList = (ArrayList)mapping_hash.get("metrics");
		// for (Object metricMapping_o : metricList){ // for each metric
		// HashMap<String, Object> metricMapping = (HashMap<String,
		// Object>)metricMapping_o;
		// String metricFormula = (String)metricMapping.get("formula"); // get
		// metric formula
		// String metricName = (String)metricMapping.get("name"); // get metric
		// name
		// ArrayList mibList = (ArrayList)metricMapping.get("mib"); // get mib
		// list
		//
		// // construct variable - value mapping ==>
		// HashMap<String, Object> variableNameValueMapping = new
		// HashMap<String, Object>();
		// ArrayList mib_value_arraylist =
		// (ArrayList)input_hashmap.get("value");
		//
		// for (Object kve : mib_value_arraylist){
		// HashMap<String, Object> kve_map = (HashMap<String, Object>)kve;
		// variableNameValueMapping.put((String)kve_map.get("mib_name"),
		// Double.parseDouble((String)kve_map.get("mib_value")));
		// }// <==
		//
		// FormulaEngine engine = FormulaEngine.GetFormulaEngine(metricFormula);
		// double result =
		// engine.variables(variableNameValueMapping).calculate();
		// result_hashmap.put(metricName, result);
		// }
		// input_hashmap.put("result", result_hashmap);
		List<Values> values = Lists.newArrayList();
		// flexjson.JSONSerializer s = new flexjson.JSONSerializer();
		// String sb = s.serialize(input_hashmap);
		// values.add(new Values(input_hashmap));
		values.add(new Values(input_hashmap, mapping_hash));
		return values;
	}

	public void declareOutputFields(OutputFieldsDeclarer declarer) {
		declarer.declare(new Fields("input", "mapping"));
	}

	public RedisDataTypeDescription getDataTypeDescription() {
		return description;
	}

	public String getKeyFromTuple(ITuple tuple) {
		return getKey(tuple);
		// HashMap map = (HashMap)tuple.getValue(0);
		// HashMap endpoint = (HashMap)map.get("endpoint");
		// String devicename = (String)endpoint.get("devicename");
		// String ip = (String)endpoint.get("ip");
		// String portname = (String)map.get("object");
		//
		// String key = String.format("mapping:d:%s:ip:%s:o:%s", devicename, ip,
		// portname);
		// return key;
	}

	private static String getKey(ITuple tuple) {
		HashMap map = (HashMap) tuple.getValue(0);
		String key = (String)map.get("mapping");
//		HashMap endpoint = (HashMap) map.get("endpoint");
//		String devicename = (String) endpoint.get("devicename");
//		String ip = (String) endpoint.get("ip");
//		String portname = (String) map.get("object");
//
//		String key = String.format("mapping:d:%s:ip:%s:o:%s", devicename, ip, portname);
		return key;
	}

	public String getValueFromTuple(ITuple tuple) {
		return null;
	}
}